package com.wenx.v3auth.listener;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.*;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.server.authorization.authentication.*;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * OAuth2认证事件监听器
 * 
 * @author wenx
 * @since 1.0.0
 */
@Slf4j
@Component
public class V3AuthEventListener {

    /**
     * 监听认证成功事件
     */
    @EventListener
    public void handleAuthenticationSuccess(AuthenticationSuccessEvent event) {
        Authentication auth = event.getAuthentication();
        
        Map<String, Object> logData = Map.of(
            "action", "认证成功",
            "principal", auth.getName(),
            "authType", auth.getClass().getSimpleName(),
            "grantType", getGrantType(auth),
            "remoteAddr", getRemoteAddress(auth)
        );
        
        log.info("[OAuth2认证] {}", JSON.toJSONString(logData));
    }

    /**
     * 监听认证失败事件
     */
    @EventListener
    public void handleAuthenticationFailure(AbstractAuthenticationFailureEvent event) {
        Authentication auth = event.getAuthentication();
        Exception ex = event.getException();
        
        Map<String, Object> logData = Map.of(
            "action", "认证失败",
            "principal", auth != null ? auth.getName() : "unknown",
            "error", ex.getMessage(),
            "errorType", ex.getClass().getSimpleName(),
            "remoteAddr", getRemoteAddress(auth)
        );
        
        log.warn("[OAuth2认证] {}", JSON.toJSONString(logData));
    }

    /**
     * 监听交互式认证成功事件（用户登录）
     */
    @EventListener
    public void handleInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
        Authentication auth = event.getAuthentication();
        
        Map<String, Object> logData = new HashMap<>();
        logData.put("action", "用户登录成功");
        logData.put("principal", auth.getName());
        logData.put("remoteAddr", getRemoteAddress(auth));
        
        if (auth.getPrincipal() instanceof UserDetails userDetails) {
            logData.put("enabled", userDetails.isEnabled());
            logData.put("authorities", userDetails.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority).toList());
        }
        
        log.info("[OAuth2认证] {}", JSON.toJSONString(logData));
    }

    /**
     * 监听权限拒绝事件
     */
    @EventListener
    public void handleAuthorizationDenied(AuthorizationDeniedEvent event) {
        Authentication auth = event.getAuthentication().get();
        
        Map<String, Object> logData = Map.of(
            "action", "权限拒绝",
            "principal", auth.getName(),
            "remoteAddr", getRemoteAddress(auth)
        );
        
        log.warn("[OAuth2认证] {}", JSON.toJSONString(logData));
    }

    /**
     * 监听密码错误事件
     */
    @EventListener
    public void handleBadCredentials(AuthenticationFailureBadCredentialsEvent event) {
        Authentication auth = event.getAuthentication();
        
        Map<String, Object> logData = Map.of(
            "action", "密码错误",
            "principal", auth.getName(),
            "remoteAddr", getRemoteAddress(auth)
        );
        
        log.warn("[OAuth2认证] {}", JSON.toJSONString(logData));
    }

    /**
     * 获取授权类型
     */
    private String getGrantType(Authentication auth) {
        if (auth instanceof OAuth2AuthorizationCodeAuthenticationToken) {
            return "authorization_code";
        } else if (auth instanceof OAuth2RefreshTokenAuthenticationToken) {
            return "refresh_token";
        } else if (auth instanceof OAuth2ClientCredentialsAuthenticationToken) {
            return "client_credentials";
        } else if (auth instanceof OAuth2AccessTokenAuthenticationToken) {
            return "access_token";
        }
        return "unknown";
    }

    /**
     * 获取远程地址
     */
    private String getRemoteAddress(Authentication auth) {
        if (auth != null && auth.getDetails() instanceof WebAuthenticationDetails webDetails) {
            return webDetails.getRemoteAddress();
        }
        return "unknown";
    }
} 